<?php

class MyPDO
{

    private $handler;
    private $stmt;

    public function __construct($config)
    {
        $dsn = 'mysql:host=' . $config['host'] . ';dbname=' . $config['dbname'];
        $options = array(
            PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8',
            PDO::ATTR_PERSISTENT => true,
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
        );

        try {
            $this->handler = new PDO($dsn, $config['username'], $config['password'], $options);
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit();
        }
    }

    public function query($sql)
    {
        $this->stmt = $this->handler->query($sql);
    }

    public function prepare($sql)
    {
        $this->stmt = $this->handler->prepare($sql);
    }

    public function bind($pos, $value, $type = null)
    {
        if (is_null($type)) {
            switch (true) {
                case is_int($value):
                    $type = PDO::PARAM_INT;
                    break;

                case is_bool($value):
                    $type = PDO::PARAM_BOOL;
                    break;

                case is_null($value):
                    $type = PDO::PARAM_NULL;
                    sbreak;

                default:
                    $type = PDO::PARAM_STR;
            }
        }
        $this->stmt->bindValue($pos, $value, $type);
    }

    public function execute()
    {
        return $this->stmt->execute();
    }

    public function select($table = '', $fields = '*', $where_sql = '', $where_data = array(), $dump = false)
    {

        $this->checkTable($table);

        $where = '';

        if (!empty($where_sql)) {
            $where = ' WHERE ' . $where_sql;
        }

        $sql = 'SELECT ' . $fields . ' FROM ' . $table . $where;

        $this->prepare($sql);

        if (!empty($where)) {
            foreach ($where_data as $k => $v) {
                $this->bind(':' . $k, $v);
            }
        }

        if ($dump == true) {
            echo $this->dumpQuery(array(), $where_data);
        }

        return true;
    }

    public function insert($table = '', $data = array(), $dump = false)
    {

        $this->checkTable($table);

        $columns = array_keys($data);

        $sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $columns) . ') VALUES (:' . implode(', :', $columns) . ')';

        $this->prepare($sql);

        foreach ($data as $k => $v) {
            $this->bind(':' . $k, $v);
        }

        if ($dump == true) {
            echo $this->dumpQuery($data, array());
        }

        $this->execute();

        return true;
    }

    public function update($table = '', $data = array(), $where_sql = '', $where_data = array(), $dump = false)
    {

        $this->checkTable($table);

        $update_columns = array();
        $where = '';

        foreach ($data as $column => $value) {
            $update_columns[] = $column . ' = :' . $column;
        }

        if (!empty($where_sql)) {
            $where = ' WHERE ' . $where_sql;
        }

        $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $update_columns) . $where;

        $this->prepare($sql);

        foreach ($data as $column => $value) {
            $this->bind(':' . $column, $value);
        }

        if (!empty($where)) {
            foreach ($where_data as $column => $value) {
                $this->bind(':' . $column, $value);
            }
        }

        if ($dump == true) {
            echo $this->dumpQuery($data, $where_data);
        }

        $this->execute();

        return true;
    }

    public function delete($table, $where_sql = '', $where_data = array(), $dump = false)
    {

        $this->checkTable($table);
        $where = '';

        if (!empty($where_sql)) {
            $where = ' WHERE ' . $where_sql;
        }

        $sql = 'DELETE FROM ' . $table . $where;

        $this->prepare($sql);

        if (!empty($where)) {
            foreach ($where_data as $column => $value) {
                $this->bind(':' . $column, $value);
            }
        }

        if ($dump == true) {
            echo $this->dumpQuery(array(), $where_data);
        }

        $this->execute();

        return true;
    }

    public function fetch()
    {
        $this->execute();
        return $this->stmt->fetch(PDO::FETCH_ASSOC);
    }

    public function fetchAll()
    {
        $this->execute();
        return $this->stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public function lastInsertId()
    {
        return $this->handler->lastInsertId();
    }

    public function rowCount()
    {
        return $this->stmt->rowCount();
    }

    public function begin()
    {
        $this->handler->beginTransaction();
    }

    public function commit()
    {
        $this->handler->commit();
    }

    public function rollback()
    {
        $this->handler->rollBack();
    }

    public function cancel()
    {
        $this->handler->cancelTransaction();
    }

    public function dumpQuery($data = array(), $where_data = array())
    {

        $sql = $this->getQuery();
        $sql = explode('WHERE', $sql);
        $first = $sql[0];
        $second = (isset($sql[1])) ? $sql[1] : null;

        foreach ($data as $k => $v) {

            $v = (is_string($v)) ? '"' . mysql_real_escape_string($v) . '"' : mysql_real_escape_string($v);

            $first = str_replace(':' . $k, $v, $first);
        }

        if ($second != null) {

            foreach ($where_data as $k => $v) {

                $v = (is_string($v)) ? '"' . mysql_real_escape_string($v) . '"' : mysql_real_escape_string($v);

                $second = str_replace(':' . $k, $v, $second);
            }
        } else {
            return $first;
        }

        $sql = $first . 'WHERE' . $second;

        return $sql;

    }

    private function getQuery()
    {
        return $this->stmt->queryString;
    }

    private function checkTable($table = '')
    {
        try {
            if (empty($table)) {
                throw new PDOException('Missing table name.');
            }
        } catch (PDOException $e) {
            echo $e->getMessage();
            exit();
        }
    }

}

$db = new MyPDO($config);